﻿using Microsoft.Extensions.DependencyInjection;
using PmSoft.Core.Domain.Entities;

namespace PmSoft.Data.Abstractions;

/// <summary>
/// 实体数据加载器
/// </summary>
/// <typeparam name="TDbContext"></typeparam>
public class CachedEntityLoader<TDbContext> : ICachedEntityLoader<TDbContext>
	where TDbContext : IDbContext
{
	private readonly IServiceProvider _serviceProvider;

	public CachedEntityLoader(IServiceProvider serviceProvider)
	{
		_serviceProvider = serviceProvider;
	}

	/// <summary>
	/// 根据 ID 集合批量获取实体
	/// </summary>
	/// <typeparam name="TEntity">实体类型</typeparam>
	/// <typeparam name="TKey">实体主键类型</typeparam>
	/// <param name="entityIds">实体 ID 集合</param>
	/// <returns>匹配的实体集合</returns>
	public async Task<IEnumerable<TEntity>> GetEntitiesByIdsAsync<TEntity, TKey>(IEnumerable<TKey> entityIds)
		where TEntity : class, IEntity<TKey>, new()
		where TKey : notnull
	{
		var repository = _serviceProvider.GetRequiredService<ICacheRepository<TDbContext, TEntity, TKey>>();
		return await repository.GetEntitiesByIdsAsync(entityIds);
	}

	/// <summary>
	/// 根据提供的键值从仓储中获取关联实体集合
	/// </summary>
	/// <typeparam name="TSource"></typeparam>
	/// <typeparam name="TAssociatedEntity"></typeparam>
	/// <typeparam name="TAssociatedKey"></typeparam>
	/// <param name="source"></param>
	/// <param name="foreignKeySelector"></param>
	/// <returns></returns>
	public async Task<IEnumerable<TAssociatedEntity>> LoadAssociatedEntitiesAsync<TSource, TAssociatedEntity, TAssociatedKey>(
		IEnumerable<TSource> source,
		Func<TSource, TAssociatedKey> foreignKeySelector)
		where TAssociatedEntity : class, IEntity<TAssociatedKey>, new()
		where TAssociatedKey : notnull
	{
		// 获取关联实体的仓储
		var associatedRepository = _serviceProvider.GetRequiredService<ICacheRepository<TDbContext, TAssociatedEntity, TAssociatedKey>>();

		// 提取外键并去重
		var foreignKeys = source.Select(foreignKeySelector).Distinct().ToList();

		// 批量加载关联实体
		var associatedEntities = await associatedRepository.GetEntitiesByIdsAsync(foreignKeys);

		return associatedEntities;
	}

	/// <summary>
	/// 根据主键加载关联实体
	/// </summary>
	/// <typeparam name="TEntity">关联实体类型</typeparam>
	/// <typeparam name="TKey">关联实体主键类型</typeparam>
	/// <param name="entityKey">关联实体的主键值</param>
	/// <returns>映射后的关联实体</returns>
	public async Task<TEntity?> GetEntityAsync<TEntity, TKey>(
		TKey entityKey)
		where TEntity : class, IEntity<TKey>, new()
		where TKey : notnull
	{
		// 获取关联实体的仓储
		var repository = _serviceProvider.GetRequiredService<ICacheRepository<TDbContext, TEntity, TKey>>();

		// 根据主键加载实体
		var entity = await repository.GetAsync(entityKey);
 
		// 执行映射并返回
		return entity;
	}
}